"""Tophub API 服务
整合 tophub.today 的热榜数据
"""
import asyncio
import aiohttp
import logging
from typing import Dict, Any, List, Optional
from datetime import datetime
import os

logger = logging.getLogger(__name__)


class TophubService:
    """Tophub API 服务类
    
    提供对 tophub.today API 的访问，获取各平台热榜数据
    """
    
    def __init__(self, apikey: str = None):
        """初始化 Tophub 服务
        
        Args:
            apikey: API 密钥，如果不提供则从环境变量读取
        """
        self.baseurl = 'https://api.tophubdata.com'
        self.apikey = apikey or os.getenv('TOPHUB_API_KEY', '1e916be7363ab9ba0042297eb18884d9')
        self.session = None
        
        # 常用节点 ID 映射
        self.node_mapping = {
            'weibo': 'KqndgxeLl9',        # 微博热搜
            'zhihu': 'mproPpoq6O',        # 知乎热榜
            'baidu': 'Jb0vmloB1G',        # 百度热搜
            'toutiao': 'x5WRR8jqWe',      # 今日头条
            'bilibili': '74Kvx59dkx',     # B站热门
            'douyin': 'DpQvNABoNE',       # 抖音热点
            'weixin': 'WnBe01o371',       # 微信热文
            'juejin': 'QaqeEaVe9R',       # 掘金热榜
            'v2ex': 'wD5vAXAebk',         # V2EX热门
            'tieba': 'Om4ejxvxEN',        # 百度贴吧
            'douban': 'Nhd2EeY0r1',       # 豆瓣热门
            'hupu': 'G47o8weMmN',         # 虎扑热帖
            'github': 'rYgqjdeGZO',       # GitHub热门
            '36kr': 'Q1Vd5Ko85R',         # 36氪热榜
            'sspai': 'Y2KeDGQdNP',        # 少数派
            'wangyi': 'DnevQmBELV',       # 网易新闻
            'pengpai': 'wWmoeN4lQJ',      # 澎湃新闻
            'xinhua': 'L4MdqkWRO1',       # 新华网热点
            'cctv': 'KMZd7VOvrO',         # 央视热点
            'ithome': '74KvxwokxM',       # IT之家
        }
    
    async def __aenter__(self):
        """异步上下文管理器入口"""
        self.session = aiohttp.ClientSession()
        return self
    
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        """异步上下文管理器出口"""
        if self.session:
            await self.session.close()
    
    async def call(self, endpoint: str, params: Dict[str, Any] = None) -> Optional[Dict[str, Any]]:
        """调用 API
        
        Args:
            endpoint: API 端点
            params: 查询参数
            
        Returns:
            API 响应数据
        """
        try:
            if not self.session:
                self.session = aiohttp.ClientSession()
            
            # 构建 URL
            url = f"{self.baseurl}{endpoint}"
            
            # 设置请求头
            headers = {'Authorization': self.apikey}
            
            # 发送请求
            async with self.session.get(url, headers=headers, params=params, timeout=30) as response:
                if response.status == 200:
                    data = await response.json()
                    return data
                else:
                    logger.error(f"Request failed with status code {response.status}")
                    return None
                    
        except asyncio.TimeoutError:
            logger.error(f"Request timeout for {endpoint}")
            return None
        except Exception as e:
            logger.error(f"Error calling API {endpoint}: {e}")
            return None
    
    async def get_nodes(self, page: int = 1) -> List[Dict[str, Any]]:
        """获取所有可用节点列表
        
        Args:
            page: 页码
            
        Returns:
            节点列表
        """
        result = await self.call("/nodes", {"p": page})
        if result and (result.get('status') == 200 or result.get('Code') == 200):
            data = result.get('data', result.get('Data', {}))
            if isinstance(data, list):
                return data
            return data.get('data', [])
        return []
    
    async def get_node_data(self, node_id: str) -> Dict[str, Any]:
        """获取指定节点的热榜数据
        
        Args:
            node_id: 节点 ID 或平台名称
            
        Returns:
            热榜数据
        """
        # 如果传入的是平台名称，转换为节点 ID
        if node_id in self.node_mapping:
            node_id = self.node_mapping[node_id]
        
        result = await self.call(f"/nodes/{node_id}", {})
        
        if result and (result.get('status') == 200 or result.get('Code') == 200):
            return result.get('data', result.get('Data', {}))
        elif result and result.get('error') == False:
            return result.get('data', {})
        return {}
    
    async def get_node_history(self, node_id: str, date: str) -> List[Dict[str, Any]]:
        """获取节点的历史数据
        
        Args:
            node_id: 节点 ID 或平台名称
            date: 日期 (格式: YYYY-MM-DD)
            
        Returns:
            历史数据列表
        """
        # 如果传入的是平台名称，转换为节点 ID
        if node_id in self.node_mapping:
            node_id = self.node_mapping[node_id]
        
        result = await self.call(f"/nodes/{node_id}/historys", {"date": date})
        
        if result and (result.get('status') == 200 or result.get('Code') == 200):
            return result.get('data', result.get('Data', []))
        return []
    
    async def search(self, query: str, page: int = 1, node_id: str = '') -> List[Dict[str, Any]]:
        """搜索内容
        
        Args:
            query: 搜索关键词
            page: 页码
            node_id: 限定在某个节点内搜索（可选）
            
        Returns:
            搜索结果列表
        """
        params = {"q": query, "p": page}
        if node_id:
            # 如果传入的是平台名称，转换为节点 ID
            if node_id in self.node_mapping:
                node_id = self.node_mapping[node_id]
            params["hashid"] = node_id
        
        result = await self.call("/search", params)
        
        if result and (result.get('status') == 200 or result.get('Code') == 200):
            data = result.get('data', result.get('Data', {}))
            if isinstance(data, list):
                return data
            return data.get('data', [])
        return []
    
    def normalize_data(self, platform: str, data: Dict[str, Any]) -> List[Dict[str, Any]]:
        """标准化数据格式
        
        Args:
            platform: 平台名称
            data: 原始数据
            
        Returns:
            标准化的数据列表
        """
        normalized = []
        
        # 获取数据列表
        items = data.get('items', [])
        if not items and 'Data' in data:
            items = data['Data'].get('data', [])
        
        for idx, item in enumerate(items):
            # 基础字段
            normalized_item = {
                'platform': platform,
                'source': 'tophub',
                'rank': idx + 1,
                'title': item.get('Title', item.get('title', '')),
                'url': item.get('Url', item.get('url', '')),
                'heat_value': item.get('HotValue', item.get('hotValue', 0)),
                'description': item.get('Description', item.get('description', '')),
                'fetch_time': datetime.utcnow().isoformat() + 'Z',
            }
            
            # 额外字段
            extra = {}
            
            # 处理不同平台的特殊字段
            if 'CreateTime' in item:
                extra['create_time'] = item['CreateTime']
            if 'UpdateTime' in item:
                extra['update_time'] = item['UpdateTime']
            if 'Extra' in item:
                extra.update(item['Extra'])
            
            # 处理热度值
            if isinstance(normalized_item['heat_value'], str):
                # 尝试提取数字
                import re
                numbers = re.findall(r'\d+', normalized_item['heat_value'])
                if numbers:
                    normalized_item['heat_value'] = int(numbers[0])
                else:
                    normalized_item['heat_value'] = 0
            
            normalized_item['extra'] = extra
            normalized.append(normalized_item)
        
        return normalized
    
    async def get_multi_platform_hot(self, platforms: List[str] = None) -> Dict[str, List[Dict[str, Any]]]:
        """获取多个平台的热榜数据
        
        Args:
            platforms: 平台列表，如果不提供则获取所有主要平台
            
        Returns:
            各平台的热榜数据
        """
        if not platforms:
            platforms = ['weibo', 'zhihu', 'baidu', 'toutiao', 'bilibili', 'douyin']
        
        results = {}
        
        for platform in platforms:
            if platform in self.node_mapping:
                try:
                    data = await self.get_node_data(platform)
                    if data:
                        normalized = self.normalize_data(platform, data)
                        results[platform] = normalized
                        logger.info(f"获取 {platform} 热榜成功: {len(normalized)} 条")
                    else:
                        results[platform] = []
                        logger.warning(f"获取 {platform} 热榜失败")
                except Exception as e:
                    logger.error(f"获取 {platform} 热榜出错: {e}")
                    results[platform] = []
                
                # 避免请求过快
                await asyncio.sleep(1)
        
        return results
    
    async def get_trending_topics(self, limit: int = 50) -> List[Dict[str, Any]]:
        """获取综合热门话题
        
        Args:
            limit: 返回数量限制
            
        Returns:
            热门话题列表
        """
        # 获取多个平台的数据
        platforms_data = await self.get_multi_platform_hot()
        
        # 合并所有数据
        all_topics = []
        for platform, items in platforms_data.items():
            all_topics.extend(items[:limit // len(platforms_data)])
        
        # 按热度值排序
        all_topics.sort(key=lambda x: x.get('heat_value', 0), reverse=True)
        
        return all_topics[:limit]


async def main():
    """测试函数"""
    logging.basicConfig(level=logging.INFO)
    
    async with TophubService() as service:
        # 测试获取节点列表
        print("\n=== 可用节点列表 ===")
        nodes = await service.get_nodes()
        for node in nodes[:5]:
            print(f"- {node.get('Name', 'N/A')}: {node.get('NodeID', 'N/A')}")
        
        # 测试获取微博热搜
        print("\n=== 微博热搜 ===")
        weibo_data = await service.get_node_data('weibo')
        if weibo_data:
            items = service.normalize_data('weibo', weibo_data)
            for item in items[:5]:
                print(f"{item['rank']}. {item['title']} - 热度: {item['heat_value']}")
        
        # 测试搜索功能
        print("\n=== 搜索测试 ===")
        search_results = await service.search('AI', page=1)
        for result in search_results[:3]:
            print(f"- {result.get('Title', 'N/A')}")
        
        # 测试多平台获取
        print("\n=== 多平台热榜 ===")
        multi_data = await service.get_multi_platform_hot(['weibo', 'zhihu', 'baidu'])
        for platform, items in multi_data.items():
            if items:
                print(f"\n{platform}: {len(items)} 条")
                for item in items[:3]:
                    print(f"  {item['rank']}. {item['title']}")
        
        return True


if __name__ == "__main__":
    result = asyncio.run(main())
    print(f"\n测试{'成功' if result else '失败'}")